package com.haima.sage.bigdata.api.frame.datatype.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.haima.sage.bigdata.api.common.NameUtils;
import com.haima.sage.bigdata.api.frame.datatype.DataTypeService;

public class DateScriptDataTypeService extends DataTypeService<Date> {
    private Pattern pattern = Pattern.compile("([+-]\\d+)(\\w+)");

    @Override
    public Date trans(Object value) {
        if (value == null) {
            return null;
        }
        String from = value.toString();
        if (!from.startsWith("now(")) {
            return null;
        }


        int index = from.indexOf(')');
        if (index == -1) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(getCurrentDate());
        String cur = from.substring(4, index);
        reset(calendar, cur);
        Matcher matcher = pattern.matcher(from);
        if (matcher.find(index)) {
            resetChange(calendar, matcher.group(1), matcher.group(2));
            while (matcher.find()) {
                resetChange(calendar, matcher.group(1), matcher.group(2));
            }
        }
        return calendar.getTime();
    }

    public  Date getCurrentDate() {
        return new Date();
    }

    private void resetChange(Calendar cal, String num, String pattern) {
        Integer dist = Integer.parseInt(num);
        pattern = NameUtils.trans(pattern);
        switch (pattern) {
            case "y":
            case "year":
            case "years":
                setChangeYear(cal, dist);
                break;
            case "M":
            case "month":
            case "months":
                setChangeMonth(cal, dist);
                break;
            case "d":
            case "day":
            case "days":
                setChangeDay(cal, dist);
                break;
            case "w":
            case "week":
            case "weeks":
                setChangeWeek(cal, dist);
                break;
            case "H":
            case "h":
            case "hour":
            case "hours":
                setChangeHour(cal, dist);
                break;
            case "m":
            case "minute":
            case "minutes":
                setChangeMinute(cal, dist);
                break;
            case "s":
            case "second":
            case "seconds":
                setChangeSecond(cal, dist);
                break;
            case "S":
            case "millisecond":
            case "milliseconds":
                setChangeMillisecond(cal, dist);
                break;

        }
    }

    private void setChangeMillisecond(Calendar cal, Integer dist) {
        cal.add(Calendar.MILLISECOND, dist);
    }

    private void setChangeSecond(Calendar cal, Integer dist) {
        cal.add(Calendar.SECOND, dist);
    }

    private void setChangeMinute(Calendar cal, Integer dist) {
        cal.add(Calendar.MINUTE, dist);
    }

    private void setChangeHour(Calendar cal, Integer dist) {
        cal.add(Calendar.HOUR, dist);
    }

    private void setChangeWeek(Calendar cal, Integer dist) {
        cal.add(Calendar.WEEK_OF_MONTH, dist);
    }

    private void setChangeDay(Calendar cal, Integer dist) {
        cal.add(Calendar.DATE, dist);
    }

    private void setChangeMonth(Calendar cal, Integer dist) {
        cal.add(Calendar.MONTH, dist);
    }

    private void setChangeYear(Calendar cal, Integer dist) {
        cal.add(Calendar.YEAR, dist);
    }

    private void reset(Calendar cal, String pattern) {
        pattern = NameUtils.transPattern(pattern);
        switch (pattern) {
            case "y":
            case "year":
            case "years":
                setCurrentYearStart(cal);
                break;
            case "M":
            case "month":
            case "months":
                setCurrentMonthStart(cal);
                break;
            case "d":
            case "day":
            case "days":
                setCurrentDayStart(cal);
                break;
            case "w":
            case "week":
            case "weeks":
                setCurrentWeekStart(cal);
                break;
            case "h":
            case "hour":
            case "hours":
                setCurrentHourStart(cal);
                break;
            case "m":
            case "minute":
            case "minutes":
                setCurrentMinuteStart(cal);
                break;
            case "s":
            case "second":
            case "seconds":
                setCurrentSecondStart(cal);
                break;
            case "S":
            case "millisecond":
            case "milliseconds":
                setCurrentMillisecondStart(cal);
                break;

        }

    }

    private void setCurrentHourStart(Calendar cal) {
        cal.set(Calendar.MINUTE, 0);
        setCurrentMinuteStart(cal);
    }

    private void setCurrentMinuteStart(Calendar cal) {
        cal.set(Calendar.SECOND, 0);
        setCurrentSecondStart(cal);
    }

    private void setCurrentSecondStart(Calendar cal) {
        cal.set(Calendar.MILLISECOND, 0);
        setCurrentMillisecondStart(cal);
    }

    private void setCurrentMillisecondStart(Calendar cal) {
    }

    private void setCurrentYearStart(Calendar cal) {
        cal.set(Calendar.MONTH, 1);
        setCurrentMonthStart(cal);
    }

    private void setCurrentMonthStart(Calendar cal) {
        cal.set(Calendar.DAY_OF_MONTH, 1);
        setCurrentDayStart(cal);
    }

    private void setCurrentWeekStart(Calendar cal) {
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);
        setCurrentDayStart(cal);
    }

    private void setCurrentDayStart(Calendar cal) {
        cal.set(Calendar.HOUR, 0);
        setCurrentHourStart(cal);
    }
}

